package de.preamp.clients.java.data;

import java.awt.datatransfer.DataFlavor;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.swing.ImageIcon;

import de.preamp.clients.java.utils.ImageCache;

/**
 * A class modeling an musical album from the database. An album belongs to one
 * or more artists and has at least one track.
 * 
 * @author André Stannek
 * @version 2010-08-02
 * @see AbstractDBItem
 * @see Artist
 * @see Track
 */
public class Album extends AbstractDBItem implements Comparable<Album>
{
    /**
     * The tracks that are on this album.
     */
    private final transient SortedSet<Track> tracks;

    /**
     * the title of this album.
     */
    private final transient String title;

    /**
     * the cover of this album.
     */
    private transient ImageIcon cover;

    /**
     * A constructor for an album with a title and cover but no tracks. The
     * cover should be the one read from the id3 APIC$03 tag or null if none in
     * tag available. The tracks have to be added by the
     * {@link #addTrack(Track) addTrack} method.
     * 
     * @param title
     *            the title of the album from the id3 TIT2 field
     * @param cover
     *            the cover of the album from the id3 APIC$03 tag or null if
     *            none in tag available
     */
    public Album(final String title, final ImageIcon cover)
    {
	super();
	this.title = title;
	this.cover = cover;
	this.tracks = new TreeSet<>();
    }

    /**
     * A constructor for an album with a title but no tracks. The tracks have to
     * be added by the {@link #addTrack(Track) addTrack} method.
     * 
     * @param title
     *            the title of the album from the id3 TIT2 field
     */
    public Album(final String title)
    {
	this(title, null);
    }

    /**
     * Returns the title of this album.
     * 
     * @return the title of the album
     */
    public final String getTitle()
    {
	return this.title;
    }

    /**
     * Returns a {@link java.util.SortedSet SortedSet} of all tracks that are
     * (currently) on this album. The tracks are sorted by
     * {@link Track#compareTo(Track) compareTo method of Track} like specified
     * in {@link java.util.SortedSet SortedSet}.
     * 
     * @return the tracks available for this album.
     */
    @Override
    public final SortedSet<Track> getTracks()
    {
	return this.tracks;
    }

    /**
     * Loads the stored id3 APIC$03 Cover of the album from or, if none
     * available, tries to load it from the image cache. If one is loaded from
     * the cache it will be stored directly as field in this object.
     * 
     * @return a cover for this album, or null if none available
     * @see de.preamp.clients.java.utils.ImageCache#getCover(String, String)
     */
    public final ImageIcon getCover()
    {
	return this.cover;
    }

    /**
     * Loads a cover from ImageChache.
     */
    public final void loadCover()
    {
	this.cover = ImageCache.getCover(this.tracks.first().getArtist(), this.title);
	fireChangeListeners();
    }

    /**
     * Adds a new track to this album, only if this album title matches the one
     * in the track and track isn't already on this album. The tracks of the
     * album will be sorted automatically by using the
     * {@link Track#compareTo(Track) compareTo method of track}.
     * 
     * @param track
     *            the new track
     */
    public final void addTrack(final Track track)
    {
	if (track.getAlbum().equals(this.title))
	{
	    this.tracks.add(track);
	    fireChangeListeners();
	}
    }

    /**
     * Returns a string representation of the overall length of this album due
     * to id3 TLEN fields of all of it's tracks.
     * 
     * @return the overall playing time as string
     */
    public final String getLengthAsString()
    {
	int length = 0;
	for (final Track track : this.tracks)
	{
	    length += track.getLength();
	}

	final int overallSeconds = length / 1000;
	final int seconds = overallSeconds % 60;
	final int minutes = overallSeconds / 60;
	final StringBuilder time = new StringBuilder();
	time.append(minutes);
	time.append(":"); //$NON-NLS-1$
	if (seconds < 10)
	{
	    time.append(0);
	}
	time.append(seconds);
	return time.toString();
    }

    @Override
    public final String toString()
    {
	return this.title;
    }

    @Override
    public final int compareTo(final Album object)
    {
	return this.title.compareTo(object.getTitle());
    }

    @Override
    public final boolean equals(final Object object)
    {
	boolean result = false;
	if (object instanceof Album)
	{
	    final Album album = (Album) object;
	    if (album.getTitle().equals(this.getTitle()))
	    {
		result = true;
	    }
	}
	return result;
    }

    @Override
    public final int hashCode()
    {
	final int prime = 31;
	int result = 1;
	result = prime * result + ((this.title == null) ? 0 : this.title.hashCode());
	return result;
    }

    @Override
    public final DataFlavor[] getTransferDataFlavors()
    {
	return new DataFlavor[] { new DataFlavor(
		DataFlavor.javaJVMLocalObjectMimeType + "; class=" //$NON-NLS-1$
			+ getClass().getName(), "Album") }; //$NON-NLS-1$
    }
}
